package com.xl6667.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xl6667.constants.SystemConstants;
import com.xl6667.domain.ResponseResult;
import com.xl6667.domain.dto.*;
import com.xl6667.domain.entity.Article;
import com.xl6667.domain.entity.ArticleTag;
import com.xl6667.domain.entity.Category;
import com.xl6667.domain.entity.User;
import com.xl6667.enums.AppHttpCodeEnum;
import com.xl6667.exception.SystemException;
import com.xl6667.mapper.ArticleMapper;
import com.xl6667.service.ArticleService;
import com.xl6667.service.ArticleTagService;
import com.xl6667.service.CategoryService;
import com.xl6667.service.UserService;
import com.xl6667.util.BeanCopyUtil;
import com.xl6667.util.EsUtil;
import com.xl6667.util.RedisCache;
import com.xl6667.util.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* @author 熊磊
* @description 针对表【sg_article(文章表)】的数据库操作Service实现
* @createDate 2024-03-13 18:13:36
*/
@Service("articleService")
@Slf4j
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>
    implements ArticleService{
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ArticleTagService articleTagService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private UserService userService;

    @Autowired
    private EsUtil esUtil;

    @Override
    public List<HotArticleDto> hotArticleList() {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        //是否为正式文章
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        //按浏览量排名
        queryWrapper.orderByDesc(Article::getViewCount);

        Page<Article> page = new Page<>(1,10);
        page(page,queryWrapper);
        List<Article> records = page.getRecords();

        return BeanCopyUtil.copyBeanList(records,HotArticleDto.class);
    }

    @Override
    public ResponseResult articleList(Integer pageNum, Integer pageSize, Long categoryId) {
        //只查询正式文章
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getStatus,SystemConstants.ARTICLE_STATUS_NORMAL);
        //对应的分类
        queryWrapper.eq(categoryId!=null,Article::getCategoryId,categoryId);
        //置顶文章
        queryWrapper.orderByDesc(Article::getIsTop);
        //分页查询
        Page<Article> page = new Page<>(pageNum,pageSize);
        page(page,queryWrapper);
        List<Article> records = page.getRecords();
        //查询分类名并封装到Dto
        List<ArticleListDto> articleListDtos = records.stream()
                .map(article -> {
                    Category byId = categoryService.getById(article.getCategoryId());
                    article.setCategoryName(byId.getName());
                    ArticleListDto articleListDto = BeanCopyUtil.copyBean(article, ArticleListDto.class);
                    return articleListDto;
                }).collect(Collectors.toList());
        PageDto pageDto = new PageDto(articleListDtos,page.getTotal());
        return ResponseResult.okResult(pageDto);
    }

    @Override
    public ResponseResult getArticle(Integer id) {
        LambdaQueryWrapper<Article> queryWrapper  = new LambdaQueryWrapper<>();
        //查询发布的文章
        queryWrapper.eq(Article::getStatus,SystemConstants.ARTICLE_STATUS_NORMAL);
        queryWrapper.eq(Article::getId,id);
        Article article = getOne(queryWrapper);
        //文章不存在
        if (article==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR);
        }
        //查询文章分类
        Category category = categoryService.getById(article.getCategoryId());
        article.setCategoryName(category.getName());
        //增加访问量存入redis
        putUpdateViewCount(article.getId());

        ArticleDto articleDto = BeanCopyUtil.copyBean(article, ArticleDto.class);
        return ResponseResult.okResult(articleDto);
    }
    @Override
    public ResponseResult putUpdateViewCount(Long id) {
        redisCache.putHashValue("article:viewCount", String.valueOf(id),1);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult getArticleList(Integer pageNum, Integer pageSize, String title, String content) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        //管理员获取所有文章
        if (!SecurityUtil.getUserType().equals( "1" )){
            queryWrapper.eq(Article::getCreateBy,SecurityUtil.getUserId());
        }

        queryWrapper.like(StringUtils.hasText(title),Article::getTitle,title);
        queryWrapper.like(StringUtils.hasText(content),Article::getContent,content);

        Page<Article> page = new Page<>(pageNum,pageSize);
        page(page,queryWrapper);
        List<Article> records = page.getRecords();

        for (Article record : records) {
            LambdaQueryWrapper<User> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(  User::getId,record.getCreateBy() );

            User one = userService.getOne( queryWrapper1 );
            if ( !Objects.isNull(one) ){
                record.setCreateName( one.getUserName() );
            }

        }

        List<SysArticleDto> sysArticleDtos = BeanCopyUtil.copyBeanList(records, SysArticleDto.class);

        PageDto pageDto = new PageDto(sysArticleDtos,page.getTotal());

        return ResponseResult.okResult(pageDto);

    }

    @Override
    public ResponseResult delArticleList(List<Long> ids) {
        LambdaUpdateWrapper<Article> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(Article::getId,ids).set(Article::getDelFlag,1);
        update(null,updateWrapper);
        for (Long id : ids) {
            try {
                esUtil.deleteDataById("article",id.toString());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return ResponseResult.okResult("删除成功");
    }

    @Override
    @Transactional
    public ResponseResult addArticle(AddArticle addarticle) {
        Article article = BeanCopyUtil.copyBean(addarticle, Article.class);
        save(article);

        List<ArticleTag> articleTags = addarticle.getTags().stream().map(tag -> new ArticleTag(article.getId(), tag)).collect(Collectors.toList());
        articleTagService.saveBatch(articleTags);
        //添加进es
        String toJSONString = JSON.toJSONString(article);
        try {
            esUtil.addData(toJSONString,"article",article.getId().toString());
        } catch (IOException e) {
            throw new SystemException(AppHttpCodeEnum.SYSTEM_ERROR);
        }
        return ResponseResult.okResult("添加成功");
    }

    @Override
    public ResponseResult getSysArticle(Long id) {
        Article article = getById(id);
        AddArticle addArticle = BeanCopyUtil.copyBean(article, AddArticle.class);
        LambdaQueryWrapper<ArticleTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArticleTag::getArticleId,id);
        List<Long> tags = articleTagService.list(queryWrapper).stream().map(ArticleTag::getTagId).collect(Collectors.toList());
        addArticle.setTags(tags);
        return ResponseResult.okResult(addArticle);
    }

    @Override
    @Transactional
    public ResponseResult putArticle(AddArticle addArticle) {
        Article article = BeanCopyUtil.copyBean(addArticle, Article.class);
        updateById(article);
        LambdaQueryWrapper<ArticleTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArticleTag::getArticleId,article.getId());
        articleTagService.remove(queryWrapper);
        List<ArticleTag> articleTags = addArticle.getTags().stream().map(tag -> new ArticleTag(article.getId(), tag)).collect(Collectors.toList());
        articleTagService.saveBatch(articleTags);

        try {
            esUtil.updateDataByIdNoRealTime(article,"article",article.getId().toString());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return  ResponseResult.okResult("修改成功");
    }

    @Override
    public ResponseResult searchArticle(Integer pageNum, Integer pageSize,String search) {
        RestHighLevelClient client = esUtil.getRestHighLevelClient();
        SearchRequest searchRequest = new SearchRequest("article");

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //搜索内容
        if ( StringUtils.hasText( search ) ){
            boolQueryBuilder.must(QueryBuilders.matchQuery("all",search));
        }
        boolQueryBuilder.must(QueryBuilders.termQuery("status",SystemConstants.ARTICLE_STATUS_NORMAL));

        searchRequest.source()
                //分页
                .size(pageSize).from((pageNum - 1) * pageSize)
                .query(boolQueryBuilder).sort("istop", SortOrder.DESC);

        SearchResponse response = null;
        try {
            response = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new SystemException(AppHttpCodeEnum.SYSTEM_ERROR);
        }

        SearchHits hits = response.getHits();
        long total = response.getHits().getTotalHits().value;

        List<Article> records = new ArrayList<>();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            Article article = JSON.parseObject(sourceAsString, Article.class);
            records.add(article);
        }
        //查询分类名并封装到Dto
        List<ArticleListDto> articleListDtos = records.stream()
                .map(article -> {
                    Category byId = categoryService.getById(article.getCategoryId());
                    article.setCategoryName(byId.getName());
                    ArticleListDto articleListDto = BeanCopyUtil.copyBean(article, ArticleListDto.class);
                    return articleListDto;
                }).collect(Collectors.toList());
        PageDto pageDto = new PageDto(articleListDtos,total);
        log.info(pageDto.getRows().toString());
        return ResponseResult.okResult(pageDto);
    }

    @Override
    public ResponseResult changeArticleStatus( Article article ) {
        updateById( article );
        return ResponseResult.okResult("修改成功");
    }

}




